#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> 
#include <sys/mman.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include "adc_spd_uio.h"
#include "math_statistics_func.h"
#include "usr_cfg.h"
#include "arm_neon.h"
#include "zlog.h"
#include "main.h"

 
adc_handle					adc_dev;
speed_handle				spd_dev;

void speed_mmap_setup(speed_handle* pspd, uint32_t data_phy_addr)
{
    pspd->spd_data_phy_addr = data_phy_addr;

    pspd->spd_axi_virt_addr = (uint32_t *)mmap(NULL, pspd->spd_axi_addr_size, PROT_READ | PROT_WRITE,
								MAP_SHARED, pspd->spd_axi_uio_fd, 0);
    if (pspd->spd_axi_virt_addr == MAP_FAILED) {
        fprintf(stderr, "pspd->axi_base_addr mmap: %s\n", strerror(errno));
		dzlog_error("pspd->spd_axi_base_addr mmap failed!");
        exit(FAILURE);
    }

    pspd->spd_data_virt_addr = (uint32_t *)mmap(NULL, SPD_CHANNEL_DATA_SIZE, PROT_READ | PROT_WRITE,
    							MAP_SHARED, pspd->mem_uio_fd, pspd->spd_data_phy_addr);
    if (pspd->spd_data_virt_addr == MAP_FAILED) {
        fprintf(stderr, "pspd->spd_data_phy_addr mmap: %s\n", strerror(errno));
		dzlog_error("pspd->spd_data_phy_addr mmap failed!");
        exit(FAILURE);
    }

	if (sys_cfg.debug == ON) {
	    printf("The speed axi lite base address %#x (lenth %#x)\n""can be accessed over\n"
	        "logical address %p\n", pspd->spd_axi_base_addr, pspd->spd_axi_addr_size, pspd->spd_axi_virt_addr);

	    printf("The speed data base address %#x (lenth %#x)\n"
	        "logical address %p\n", pspd->spd_data_phy_addr, SPD_CHANNEL_DATA_SIZE, pspd->spd_data_virt_addr);
		printf("############################################################\n");
	}
}



void adc_mmap_setup(adc_handle* padc, uint32_t data_phy_addr)
{
    padc->adc_data_phy_addr = data_phy_addr;

    padc->adc_axi_virt_addr = (uint32_t *)mmap(NULL, padc->adc_axi_addr_size, PROT_READ | PROT_WRITE, 
								MAP_SHARED, padc->adc_axi_uio_fd, 0);
    if (padc->adc_axi_virt_addr == MAP_FAILED) {
        fprintf(stderr, "padc->adc_axi_base_addr mmap: %s\n", strerror(errno));
		dzlog_error("padc->adc_axi_base_addr mmap failed!");
        exit(FAILURE);
    }

    padc->adc_data_virt_addr = (uint32_t *)mmap(NULL, AD_CHANNEL_DATA_SIZE, PROT_READ | PROT_WRITE, //预留内存32MB
    							MAP_SHARED, padc->mem_uio_fd, padc->adc_data_phy_addr);	//每通道4MB空间
    if (padc->adc_data_virt_addr == MAP_FAILED) {
        fprintf(stderr, "padc->ad_data_phy_addr mmap: %s\n", strerror(errno));
		dzlog_error("padc->ad_data_phy_addr mmap failed!");
        exit(FAILURE);
    }

	arm_fill_f32(0.0, (float*)padc->adc_data_virt_addr, (AD_CHANNEL_DATA_SIZE >> 2));

	if (sys_cfg.debug == ON) {
	    printf("The adc axi lite base address %#x (lenth %#x)\n""can be accessed over\n"
	        "logical address %p\n", padc->adc_axi_base_addr, padc->adc_axi_addr_size, padc->adc_axi_virt_addr);

	    printf("The adc data base address %#x (lenth %#x)\n"
	        "logical address %p\n", padc->adc_data_phy_addr, AD_CHANNEL_DATA_SIZE, padc->adc_data_virt_addr);
		printf("############################################################\n");
	}
}

inline __attribute__((always_inline)) void adc_axi_reg_set(adc_handle *padc, uint32_t offset, uint32_t val) 
{
    *(padc->adc_axi_virt_addr + offset) = val;
}

inline __attribute__((always_inline)) void adc_axi_reg_setf(adc_handle *padc, uint32_t offset, float val) 
{
    *(float *)(padc->adc_axi_virt_addr + offset) = val;
}


inline __attribute__((always_inline)) uint32_t adc_axi_reg_get(adc_handle *padc, uint32_t offset) 
{
    return *(padc->adc_axi_virt_addr + offset);
}


inline __attribute__((always_inline)) uint32_t speed_axi_reg_get(speed_handle *pspd, uint32_t offset) 
{
    return *(pspd->spd_axi_virt_addr + offset);
}


void adc_init(sys_cfg_info *sys, adc_handle *padc, chx_cfg_info chx[])
{	
	adc_axi_reg_set(padc, ADS1672_REG1_OFFSET, 0x00);   			// reset low active
    adc_axi_reg_set(padc, ADS1672_REG0_OFFSET, 0x00);   			// stop
    
    adc_axi_reg_setf(padc, ADS1672_REG5_OFFSET, chx[0].chx_calib); 
    adc_axi_reg_setf(padc, ADS1672_REG6_OFFSET, chx[1].chx_calib);
    adc_axi_reg_setf(padc, ADS1672_REG7_OFFSET, chx[2].chx_calib);
    adc_axi_reg_setf(padc, ADS1672_REG8_OFFSET, chx[3].chx_calib);
    adc_axi_reg_setf(padc, ADS1672_REG9_OFFSET, chx[4].chx_calib);
    adc_axi_reg_setf(padc, ADS1672_REG10_OFFSET, chx[5].chx_calib);
    adc_axi_reg_setf(padc, ADS1672_REG11_OFFSET, chx[6].chx_calib);
    adc_axi_reg_setf(padc, ADS1672_REG12_OFFSET, chx[7].chx_calib);
    usleep(20000);
    adc_axi_reg_set(padc, ADS1672_REG1_OFFSET, 0x01);   			// unable reset

	padc->irq_cnt =  (uint16_t)((sys->samp_freq * sys->duration) / PING_PANG_FIFO_SIZE) + 1;
	if ((padc->irq_cnt % 2) > 0)									// 64KB地址空间对齐，貌似很重要
		padc->irq_cnt += 1;
	if (padc->irq_cnt >= 502)
		padc->irq_cnt = 502;										//409600 * 10秒，最大500
	adc_axi_reg_set(padc, ADS1672_REG4_OFFSET, padc->irq_cnt);
	printf("ads1672 reg4 irq_cnt_reg set is %d\n", padc->irq_cnt);

	switch (sys->samp_freq) 
	{
		case 25600 :
			adc_axi_reg_set(padc, ADS1672_REG2_OFFSET, 25600); 		// sample freq 
			break;
		case 51200 :
			adc_axi_reg_set(padc, ADS1672_REG2_OFFSET, 51200);
			break;
		case 102400 :
			adc_axi_reg_set(padc, ADS1672_REG2_OFFSET, 102400);
			break;
		case 204800 :
			adc_axi_reg_set(padc, ADS1672_REG2_OFFSET, 204800);
			break;
		case 409600 :
			adc_axi_reg_set(padc, ADS1672_REG2_OFFSET, 409600);
			break;
		default :
			adc_axi_reg_set(padc, ADS1672_REG2_OFFSET, 102400);
			break;
	}
		
    adc_axi_reg_set(padc, ADS1672_REG3_OFFSET, 0x01);   		//clean interrupt flag
    adc_axi_reg_set(padc, ADS1672_REG0_OFFSET, 0xFF);   		//start

	if (sys->debug == ON) {
   		printf("ads1278 init is finished! \n");
	}
}


